package com.lse_from.utils

import org.springframework.util.StringUtils
import java.awt.Color
import java.awt.Font
import java.awt.Graphics2D
import java.awt.RenderingHints
import java.awt.geom.AffineTransform
import java.awt.image.BufferedImage
import java.io.File
import java.io.FileInputStream
import java.lang.Exception
import java.util.stream.Collectors
import javax.imageio.ImageIO

/**
 * 图片生成工具
 *
 * @author 祁雪
 */
class ImageBusinessUtil {

    companion object {

        /**
         * 创建一个指定宽高的image
         *
         * @param width
         * @param height
         * @return
         */
        fun createImage(width: Int, height: Int): BufferedImage {
            return BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
        }

        /**
         * 创建指定宽高的image
         *
         * @param width
         * @param height
         * @param alpha  透明度 0-255
         * @return
         */
        fun createImageTrWhite(
            width: Int,
            height: Int,
            alpha: Int,
            vararg rgbs: Int?
        ): BufferedImage {
            val bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR)

            // 设置透明颜色(较透明)
            // 获取画笔
            val graphics2D = bufferedImage.createGraphics()
            graphics2D.drawImage(bufferedImage, 0, 0, null)
            val color = Color(
                (if (rgbs.size >= 1) rgbs[0] else 255)!!,
                (if (rgbs.size >= 2) rgbs[1] else 255)!!,
                (if (rgbs.size >= 3) rgbs[2] else 255)!!, alpha
            )
            for (x in 0 until bufferedImage.width) {
                for (y in 0 until bufferedImage.height) {
                    bufferedImage.setRGB(x, y, color.rgb)
                }
            }
            // 绘制新RGB
            graphics2D.drawImage(bufferedImage, 0, 0, null)
            graphics2D.dispose()
            return bufferedImage
        }

        /**
         * 创建一个基于图片文件指定宽高的 image
         *
         * @param width     指定宽
         * @param height    指定高
         * @param imageFile 图片文件
         * @param getCenter 是否取用上下左右居中
         * @return
         * @throws Exception
         */
        @Throws(Exception::class)
        fun createImage(
            widthSou: Int, heightSou: Int,
            imageFile: File,
            getCenter: Boolean
        ): BufferedImage {
            var width = widthSou
            var height = heightSou
            val sourceImage = ImageIO.read(imageFile)

            // 开始位置的宽高
            var centerW = 0
            var centerH = 0
            if (width < sourceImage.width) {
                centerW = (sourceImage.width - width) / 2
            } else {
                width = sourceImage.width
            }
            if (height < sourceImage.height) {
                centerH = (sourceImage.height - height) / 2
            } else {
                height = sourceImage.height
            }
            val bufferedImage = createImage(width, height)
            for (x in 0 until width) {
                for (y in 0 until height) {
                    // 是否取中间
                    if (getCenter) {
                        bufferedImage.setRGB(x, y, sourceImage.getRGB(x + centerW, y + centerH))
                    } else {
                        bufferedImage.setRGB(x, y, sourceImage.getRGB(x, y))
                    }
                }
            }
            return bufferedImage
        }

        /**
         * 图片重叠
         *
         * @param bufferedImages
         */
        fun imageOverlap(bufferedImages: Array<BufferedImage>): BufferedImage? {
            var width = 0
            var height = 0
            var graphics2D: Graphics2D? = null
            var source: BufferedImage? = null
            for (i in 0 until bufferedImages.size) {
                val bufferedImage = bufferedImages[i]
                if (i == 0) {
                    width = bufferedImage.width
                    height = bufferedImage.height
                    source = bufferedImage
                    graphics2D = bufferedImage.createGraphics()
                    graphics2D.drawImage(source, 0, 0, null)
                    continue
                }
                assert(graphics2D != null)
                graphics2D!!.drawImage(bufferedImage, 0, 0, null)
            }
            graphics2D?.dispose()
            return source
        }

        /**
         * 输出图片
         *
         * @param bufferedImage
         * @param outFile
         * @throws Exception
         */
        @Throws(Exception::class)
        fun outPutImage(
            bufferedImage: BufferedImage?,
            outFile: File
        ) {
            outFile.parentFile.mkdirs()

            val fileType = outFile.name.substring(outFile.name.lastIndexOf(".") + 1)
            ImageIO.write(bufferedImage, fileType, outFile)
        }

        /**
         * 插入内容
         */
        @Throws(Exception::class)
        fun setContent(
            sourceImage: BufferedImage,
            contentList: ArrayList<ImageContent>
        ): BufferedImage {
            val width = sourceImage.width
            val graphics2D = sourceImage.createGraphics()
            // 设置抗锯齿
            graphics2D.setRenderingHint(
                RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB
            )

            var offsetText = 0
            var offsetImage = 0
            contentList.forEach { content ->
                if (content.isText) {
                    offsetText = setTextContent(content, graphics2D, width, offsetText)
                } else {
                    offsetImage = setImageContent(content, graphics2D, offsetImage)
                }
            }
            graphics2D.dispose()
            return sourceImage
        }


        /**
         * 填入文字内容
         *
         * @param content
         * @param graphics2D
         * @param width
         * @param offsetYSou
         */
        fun setTextContent(
            content: ImageContent,
            graphics2D: Graphics2D,
            width: Int, offsetYSou: Int
        ): Int {
            var offsetY = offsetYSou
            val fontSize = Math.max(content.fontSize, 14)
            var font: Font? = null
            font = if (content.outSideTTFPath.isNullOrBlank()) {
                Font(content.familyName, if (content.isBold) Font.BOLD else Font.PLAIN, fontSize)
            } else {
                createFont(
                    content.outSideTTFPath!!,
                    fontSize.toString().toFloat(),
                    content.isBold
                )
            }
            graphics2D.color = content.color
            graphics2D.font = font
            // 判定字符长度
            val charSize: Int = content.text.length * fontSize
            val texts: MutableList<List<Char>> = java.util.ArrayList()
            if (charSize > width - content.x) {
                // 向上取整
                val brCount = Math.ceil(charSize.toDouble() / (width - content.x).toDouble()).toInt()
                // 文字拆分成brCount份
                val chars: MutableList<Char> = java.util.ArrayList()
                for (c in content.text.toCharArray()) {
                    chars.add(c)
                }
                val size = chars.size / brCount
                for (i in 0 until brCount) {
                    texts.add(
                        chars.subList(
                            if (i == 0) 0 else i * size + 1,
                            Math.min(i * size + size + 1, chars.size)
                        )
                    )
                }
            }
            if (texts.size != 0) {
                for (i in texts.indices) {
                    val text = texts[i]
                    graphics2D.drawString(text.stream().map { obj: Char -> obj.toString() }
                        .collect(Collectors.joining("")), content.x, content.y + offsetY)
                    if (i != texts.size - 1) {
                        offsetY += fontSize + 10
                    }
                }
                return offsetY
            }
            graphics2D.drawString(content.text, content.x, content.y + offsetY)
            return offsetY
        }

        /**
         * 写入图片数据
         *
         * @param content
         * @param graphics2D
         * @param offsetYSou
         * @throws Exception
         */
        @Throws(Exception::class)
        fun setImageContent(
            content: ImageContent,
            graphics2D: Graphics2D,
            offsetYSou: Int
        ): Int {
            var offsetY = offsetYSou
            if (content.imagePath.isNullOrBlank()) {
                return offsetY
            }
            val file: File = File(content.imagePath!!)
            if (!file.exists()) {
                return offsetY
            }
            var image = ImageIO.read(file)

            // 采取缩放
            if (content.imageResHeight > 0 && content.imageResWidth > 0) {
                image = resizeImage(
                    image,
                    content.imageResWidth,
                    content.imageResHeight,
                    false
                )
            }
            // 写入图片
            graphics2D.drawImage(image, content.x, content.y + offsetY, null)
            offsetY += image.height + 10
            return offsetY
        }

        /**
         * 使用外部文字
         * @param path 外部文字地址 绝对路径
         * @param fontSize 字体大小
         * @param isBold 是否加粗
         */
        fun createFont(
            path: String,
            fontSize: Float,
            isBold: Boolean
        ): Font {

            val fileInputStream = FileInputStream(File(path))

            fileInputStream.use {

                val font = Font.createFont(Font.TRUETYPE_FONT, it)

                return font.deriveFont(if (isBold) Font.BOLD else Font.PLAIN, fontSize)
            }
        }


        /**
         * 图片缩放
         *
         * @param sourceImage
         * @param targetW
         * @param targetH
         * @param isGeometric 是否等比比例缩放
         * @return
         */
        fun resizeImage(
            sourceImage: BufferedImage,
            targetWidth: Int,
            targetHeight: Int,
            isGeometric: Boolean
        ): BufferedImage {
            var targetW = targetWidth
            var targetH = targetHeight

            val type = sourceImage.type
            var targetImage: BufferedImage? = null

            // 如果是等比缩放
            var sx = targetW.toDouble() / sourceImage.width
            var sy = targetH.toDouble() / sourceImage.height
            if (isGeometric) {
                if (sx < sy) {
                    sx = sy
                    targetW = (sx * sourceImage.width).toInt()
                } else {
                    sy = sx
                    targetH = (sy * sourceImage.height).toInt()
                }
            }
            targetImage = if (type == BufferedImage.TYPE_CUSTOM) {
                val cm = sourceImage.colorModel
                val raster = cm.createCompatibleWritableRaster(targetW, targetH)
                val alphaPremultiplied = cm.isAlphaPremultiplied
                BufferedImage(cm, raster, alphaPremultiplied, null)
            } else {
                BufferedImage(targetW, targetH, type)
            }
            val graphics2D = targetImage.createGraphics()
            graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC)
            graphics2D.drawRenderedImage(sourceImage, AffineTransform.getScaleInstance(sx, sy))
            graphics2D.dispose()

            return targetImage
        }

    }

    /**
     * 图片内容实体
     */
    open class ImageContent {

        var text: String = ""

        var x: Int = 0;

        var y: Int = 0;

        var fontSize: Int = 14;

        var color: Color = Color.BLACK

        var isBold: Boolean = false

        var familyName: String = "微软雅黑"

        /**
         * 是否是文字内容
         */
        var isText = true

        /**
         * 图片内容的绝对路径
         */
        var imagePath: String? = null

        /**
         * 图片缩放的宽度 0.原始宽度
         */
        var imageResWidth = 0

        /**
         * 图片缩放的高度 0.原始高度
         */
        var imageResHeight = 0

        /**
         * 外部文字路径
         */
        var outSideTTFPath: String? = null

    }

}

fun main() {

    val bgPath =
        "C:\\Users\\76167\\Desktop\\文档数据\\原神QQ机器人素材\\7dfae49866576b58dca501250ecd32e3_2662190375670020009.png"

    val avtarImagePath = "C:\\Users\\76167\\Desktop\\文档数据\\test\\QQ消息图片生成测试\\2`{W6ZX$68TW1FIW0UY[WU8.bmp"

    val descPath = "C:\\Users\\76167\\Desktop\\文档数据\\test\\图片测试.png"
    /*outPutImage(createImage(800, 350, new File(bgPath), true),
                new File(descPath));*/

    /*outPutImage(createImage(800, 350, new File(bgPath), true),
                new File(descPath));*/
    val width = 340
    val height = 180

    val contentList = arrayListOf<ImageBusinessUtil.ImageContent>(
        ImageBusinessUtil.ImageContent().let {
            it.isText = false
            it.imagePath = avtarImagePath
            it.imageResWidth = 80
            it.imageResHeight = 80
            it.x = 10
            it.y = 20
            it
        },
        ImageBusinessUtil.ImageContent().let {
            it.text = "QQ昵称阿斯顿撒旦撒旦撒"
            it.color = Color.lightGray
            it.fontSize = 24
            it.x = 100
            it.y = 30
            it
        },
        ImageBusinessUtil.ImageContent().let {
            it.text = "内容大家按时可见度看见你尽快发送的艰苦奋斗撒恢复45645但凡定时5法  点粉丝4斯蒂芬 是"
            it.fontSize = 24
            it.x = 100
            it.y = 80
            it
        }
    )

    ImageBusinessUtil.outPutImage(
        ImageBusinessUtil.setContent(
            ImageBusinessUtil.createImageTrWhite(width * 2, height * 2, 255, 255, 255, 255),
            contentList
        ),
        File(descPath)
    )

    /*ImageBusinessUtil.outPutImage(
        ImageBusinessUtil.setContent(
            ImageBusinessUtil.imageOverlap(
                arrayOf(
                    ImageBusinessUtil.createImage(width, height, File(bgPath), true),
                    ImageBusinessUtil.createImageTrWhite(width, height, 100)
                )
            )!!, contentList
        ),
        File(descPath)
    )*/
}